#ifndef TOOLS_FUNC_H
#define TOOLS_FUNC_H

#include <errno.h>
#include <signal.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <libgen.h>


/**
 * @brief 安全的free函数，若指针为NULL则不进行操作
 * @param ptr 要释放的指针
 */
static inline void safe_free(void* ptr) {
    if (ptr) {
        free(ptr);
    }
}

/**
 * @brief 申请内存，并初始化为0
 * @param size 申请的内存大小
 * @return 申请的内存块的指针
 */
static inline void* zalloc(size_t size) {
    void* ptr = malloc(size);
    if (ptr) {
        memset(ptr, 0, size);
    }
    return ptr;
}

/**
 * @brief 计算base的exponent次方
 * @param base 底数
 * @param exponent 指数
 * @return base的exponent次方
 */
static inline long long power_integer(long long base, int exponent) {
    if (exponent == 0) {
        return 1;
    } else {
        return base * power_integer(base, exponent - 1);
    }
}

/**
 * @brief 运行shell命令，并返回命令的执行结果
 * @param terminal_output_buf 终端输出字符串的缓冲区，若不需要则传入NULL
 * @param output_buf_size 终端输出字符串的缓冲区大小
 * @param cmd 要运行的shell命令
 * @return 命令的执行结果
 */
#define PRINT_RUN_CMD_LOG 1
#define NO_PRINT_RUN_CMD_LOG 0
static inline long long run_shell_cmd(char *terminal_output_buf, int output_buf_size, const char *cmd, int print_flag)
{
    long long ret = 0;
    FILE *fp = popen(cmd, "r");
    if (fp == NULL) {
        printf("Failed to run command: %s\n", cmd);
        return -1;
    }
    if (print_flag == PRINT_RUN_CMD_LOG) {
        printf("Running command: %s\n", cmd);
    }
    // 如果关心终端输出字符串，可以用fgets()函数读取输出
    if (terminal_output_buf) {
        char read_line[1024] = {0};
        int outbuf_offset = 0;
        while (fgets(read_line, sizeof(read_line) - 1, fp) != NULL) {
            int read_line_len = strlen(read_line);
            if ((outbuf_offset + read_line_len) > output_buf_size) {
                printf("WARN cmd[%s] out str len[%d] > output_buf_size[%d].\n", cmd, outbuf_offset + read_line_len, output_buf_size);
                break;
            }
            memcpy(terminal_output_buf + outbuf_offset, read_line, read_line_len);
            outbuf_offset += read_line_len;
        }
        ret = 0;
    }
    else {
        char gets_buf[1024];
        // 读取命令输出，并解析结果
        if (fgets(gets_buf, sizeof(gets_buf), fp) != NULL) {
            // 如果输出0x开头的十六进制数，按十六进制解析
            if (strncmp(gets_buf, "0x", 2) == 0) {
                ret = strtoll(gets_buf, NULL, 16);
            }
            // 否则按十进制解析
            else {
                ret = strtoll(gets_buf, NULL, 10);
            }
        }
    }
    pclose(fp);
    return ret;
}

// 判断PID是否存在
static inline int pid_exists(uint64_t pid)
{
    if (kill(pid, 0) == 0) {
        return 1; // PID exists
    } else if (errno == ESRCH) {
        return 0; // PID does not exist
    } else {
        perror("kill");
        return -1; // Error occurred
    }
}

/*****************************************************
 *  函数功能：以keyword为特征值剪切字符串。
 *  输入参数：
 *      output_buf: 数组[128]指针，用于存放剪切结果；
 *      output_buf_len: output_buf可操作大小；
 *      input_str: 输入字符串的起始地址；
 *      input_len: 输入字符串的长度；
 *      keyword：关键字；
 * 输出参数：
 *      output_buf：剪切好的字符依次放入output_buf[0][128]、output_buf[1][128]...
 *  返回值：
 *      剪切出的元素个数。
 * 
 *  示例：
 *      char output_buf[2][128];
 *      int output_buf_len = sizeof(output_buf);
 *      char input_str[] = "hello world, hello tcpa";
 *      int input_len = strlen(input_str);
 *      int output_num = cut_str_for_keyword(output_buf, output_buf_len, input_str, input_len, "world");
 *      printf("output_num = %d\n", output_num);
 *      for (int i = 0; i < output_num; i++) {
 *          printf("%s\n", output_buf[i]);
 *      }
 *  输出：
 *      output_num = 2
 *      output_buf[0] = "hello "
 *      output_buf[1] = ", hello tcpa"
 * 
 ******************************************************/
static inline int cut_str_for_keyword(char (*output_buf)[128], const int output_buf_len, const char* input_str, const int input_len, const char* keyword)
{
    int i = 0, j = 0, k = 0;
    const int output_buf_size = 128;
    int output_buf_num = output_buf_len / output_buf_size;
    memset(output_buf[0], 0, output_buf_size);

    // 去除输入字符串有效数据之前的空格与换行
    while ((input_str[i] == ' ') || (input_str[i] == '\n')) {
        i++;
    }

    // 遍历输入字符串
    for (; i < input_len; i++) {
        // 检测分割符号
        if(input_str[i] == keyword[0]) {
            
            // 分隔符匹配成功
            if (memcmp(input_str + i, keyword, strlen(keyword)) == 0) {
                i += (strlen(keyword) - 1); // -1 是减去在keyword最后的'\0'计算

                // 输出 buf 空间是否足够
                if(k < output_buf_num) {                    
                    k++;
                    j = 0;
                    memset(output_buf[k], 0, output_buf_size);
                }
                else {
                    break;
                }

            }
            else {
                if(j < output_buf_size) {
                    output_buf[k][j++] = input_str[i];
                }
            }
            
        }
        else {
            if (j < output_buf_size) {
                output_buf[k][j++] = input_str[i];
            }
        }
    }
    // 遍历完输入字符串后，若不是以分隔符结束，则需要再次累加剪切出的元素个数
    if (i == input_len) {
        k++;
    }

    return k;
}

/**
 * @brief 设置文件描述符为非阻塞模式
 * @param fd 文件描述符
 */
static inline void set_nonblocking(int fd) {
    int flags = fcntl(fd, F_GETFL, 0);
    fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

/**
 * @brief 判断目录是否存在
 * @param path 目录路径
 * @return 1：存在；0：不存在
 */
static inline int is_directory_exist(const char *path) {
    struct stat info;

    // 使用 stat 获取文件或目录信息
    if (stat(path, &info) != 0) {
        // stat 调用失败
        return 0;
    }

    // 检查是否为目录
    if (S_ISDIR(info.st_mode)) {
        return 1;
    } else {
        return 0;
    }
}

/**
 * @brief 创建目录
 * @param path 目录路径
 * @return 0：成功；-1：失败
 */
static inline int create_directory(const char *path) {
    // 检查目录是否存在
    if (is_directory_exist(path) == 1) {
        return 0;
    }

    // 使用 mkdir 创建目录，权限设置为 0777
    if (mkdir(path, 0777) == -1) {
        // 检查错误类型
        if (errno != EEXIST) {
            return -1;
        }
    }
    return 0;
}

/**
 * @brief 打开文件（如果不存在，自动创建目录与文件）
 * @param path 文件路径
 * @param flags 打开模式
 * @return 文件描述符
 */
static inline FILE *open_file_with_create_dir(const char *file_path, char *flags) {

    // 提取目录
    // 创建一个可修改的字符串副本
    char *file_path_copy = strdup(file_path);
    if (file_path_copy == NULL) {
        perror("Error duplicating string");
        return NULL;
    }
    // 使用 dirname 提取目录部分
    char *dir_path = dirname(file_path_copy);

    // 创建目录
    char mkdir_cmd[1024] = {0};
    snprintf(mkdir_cmd, sizeof(mkdir_cmd), "mkdir -p %s", dir_path);
    system(mkdir_cmd);

    // 打开文件
    return fopen(file_path, flags);
}

/**
 * @brief 判断文件是否存在
 * @param path 文件路径
 * @return 1：存在；0：不存在
 */
static inline int is_file_exist(const char *path) {
    return access(path, F_OK) == 0;
}


#endif